#include "StdAfx.h"
#include "DX10ObjMesh.h"

#include "ContentManager.h"
#include "RenderContext.h"
#include "InputState.h"
#include "DX10MaterialIndexBuffer.h"
#include "Skeleton.h"
#include "GraphCamera.h"
#include "Level.h"
#include "PhysicsMesh.h"


#include "StdAfx.h"
#include "DX10ObjMesh.h"

#include "ContentManager.h"
#include "RenderContext.h"
#include "InputState.h"
#include "DX10MaterialIndexBuffer.h"
#include "Skeleton.h"
#include "GraphCamera.h"
#include "Level.h"
#include "PhysicsMesh.h"


DX10ObjMesh::DX10ObjMesh(tstring effect,tstring technique):
        m_EffectFileName(effect),
		m_TechiqueName(technique),
        m_pVertexBuffer(NULL),
        m_pInputLayout(NULL),
        m_pSkeleton(NULL),
        m_pDiffuseMapVariable(NULL),
        m_pEyePosVariable(NULL),
        m_pSpotLight1Variable(NULL),
        m_pSpotLight2Variable(NULL),
        m_pWorldVariable(NULL),
        m_pWorldViewProjectionVariable(NULL),
        m_pBoneMatrices(NULL),
        m_pDefaultEffect(NULL),
        m_pDefaultTechnique(NULL),
        m_SynchronizeWithPhysics(false),
        m_pActor(NULL)
{
        

        //Rotate(D3DXVECTOR3(-1.57079633f,0,0));
        Translate(D3DXVECTOR3(0,0,0));
}
DX10ObjMesh::~DX10ObjMesh(void)
{
        SAFE_RELEASE(m_pVertexBuffer);
        SAFE_RELEASE(m_pInputLayout);
        vector<DX10MaterialIndexBuffer*>::iterator it;
        for (it = m_IndexBuffers.begin(); it != m_IndexBuffers.end(); ++it )
        {
                delete *it;
        }
        SAFE_DELETE(m_pSkeleton);
}

void DX10ObjMesh::CreateEffect(ContentManager *pContentManager)
{
	if ( !m_pDefaultEffect->IsValid())
	{
		m_pDefaultEffect = pContentManager->GetEffect(m_pLevel->GetDevice(), _T("./Effect/Phong.fx"));//m_EffectFileName);	

		//get first technique found
		m_pDefaultTechnique = m_pDefaultEffect->GetTechniqueByName("TechAnisotropic");

		GetEffectVariables(m_pDefaultEffect);
	}
}

void DX10ObjMesh::CreateEffect(ContentManager *pContentManager, ID3D10Device* pDevice){
        m_pDefaultEffect = pContentManager->GetEffect(pDevice, m_EffectFileName);      

        //get first technique found
        m_pDefaultTechnique = m_pDefaultEffect->GetTechniqueByIndex(0);
		//m_pDefaultTechnique = m_pDefaultEffect->GetTechniqueByName(m_TechiqueName);
        GetEffectVariables(m_pDefaultEffect);
}

void DX10ObjMesh::GetEffectVariables(ID3D10Effect* effect){
        m_pWorldViewProjectionVariable = effect->GetVariableByName("gWVP")->AsMatrix();
        //if(!m_pWorldViewProjectionVariable->IsValid())MessageBox(0,_T("Getting Effectvariable gWVP Failed"),_T("ERROR"),0);

        m_pWorldVariable                        = effect->GetVariableByName("gWorld")->AsMatrix();
        //if(!m_pWorldVariable->IsValid())MessageBox(0,_T("Getting Effectvariable gWorld Failed"),_T("ERROR"),0);

        m_pDiffuseMapVariable = effect->GetVariableByName( "gDiffuseMap" )->AsShaderResource();
        //if(!m_pDiffuseMapVariable->IsValid())MessageBox(0,_T("Getting Effectvariable gDiffuseMap Failed"),_T("ERROR"),0);

        m_pNormalMapVariable = effect->GetVariableByName( "gNormalMap" )->AsShaderResource();
        //if(!m_pNormalMapVariable->IsValid())MessageBox(0,_T("Getting Effectvariable gNormalMap Failed"),_T("ERROR"),0);

        m_pSpotLight1Variable = effect->GetVariableByName("gLight1");
        //if(!m_pSpotLight1Variable->IsValid())MessageBox(0,_T("Getting Effectvariable gLight1 Failed"),_T("ERROR"),0);
        m_pSpotLight2Variable = effect->GetVariableByName("gLight2");
        //if(!m_pSpotLight2Variable->IsValid())MessageBox(0,_T("Getting Effectvariable gLight1 Failed"),_T("ERROR"),0);

        m_pEyePosVariable = effect->GetVariableByName("EyePos")->AsVector();
        //if(!m_pEyePosVariable->IsValid())MessageBox(0,_T("Getting Effectvariable EyePos Failed"),_T("ERROR"),0);

        if (IsAnimated())
        {
                m_pBoneMatrices = m_pDefaultEffect->GetVariableByName("gBoneMatrices");
                if(!m_pBoneMatrices->IsValid())MessageBox(0,_T("Getting Effectvariable gBoneMatrices Failed"),_T("ERROR"),0);
        }
}

void  DX10ObjMesh::UpdateEffectVariables(const RenderContext* context)const
{
        //
    // Update Shader matrix variables in effect
    //
        //create a matrix containing the multiplication of world, view and projection matrix
        //short: m_pWorldViewProjectionVariable->SetMatrix((float*)&(m_World * m_View * m_Projection));
        //bit longer:
        D3DXMATRIX wvp;
        if ( m_SynchronizeWithPhysics && m_pActor){
                NxActor* pActor = m_pActor->GetActor();
                pActor->getGlobalPose().getColumnMajor44((NxF32*)&wvp.m);
                m_pWorldVariable->SetMatrix((float*)&wvp);
        }else{
                wvp = this->GetWorldMatrix();
                m_pWorldVariable->SetMatrix((float*)&this->GetWorldMatrix());
        }
        GraphCamera* camera = context->GetCamera();
        wvp = wvp * camera->GetViewProj();
        m_pWorldViewProjectionVariable->SetMatrix((float*)&wvp);
       

        if ( IsAnimated() )
        {
                m_pBoneMatrices->SetRawValue( (void*)m_pSkeleton->GetValuePointer(),0,m_pSkeleton->GetSizeInBytes());
        }
        /*
        int spotlightsize = sizeof(SpotLight);
        if ( m_SpotLights.size()>0 )
                m_pSpotLight1Variable->SetRawValue((void*)m_SpotLights[0],0,sizeof(SpotLight));
        if ( m_SpotLights.size()>1)
                m_pSpotLight2Variable->SetRawValue((void*)m_SpotLights[1],0,sizeof(SpotLight));
        */

        D3DXVECTOR3 pos = camera->GetPos();
        m_pEyePosVariable->SetRawValue(&pos,0,sizeof(D3DXVECTOR3));
}

void DX10ObjMesh::SetDiffuseTexture(ID3D10ShaderResourceView *texture) const{
        m_pDiffuseMapVariable->SetResource(texture);
}

void DX10ObjMesh::SetNormalMapTexture(ID3D10ShaderResourceView * texture) const{
        m_pNormalMapVariable->SetResource(texture);
}

void DX10ObjMesh::SetSkeleton(Skeleton* pSkeleton)
{
        m_pSkeleton = pSkeleton;
       
}

void DX10ObjMesh::AddAnimation(Animation * pAnimation){
        if (IsAnimated())
                m_pSkeleton->AddAnimation(pAnimation);
}

void DX10ObjMesh::AddAnimation( AnimationPtr animation){
        if( IsAnimated())
                m_pSkeleton->AddAnimation(animation);
}

void DX10ObjMesh::ActivateAnimation(tstring key,bool looping)const{
        if (IsAnimated())
                m_pSkeleton->ActivateAnimation(key,looping);
}

void DX10ObjMesh::Initialize(ContentManager* contentManager,ID3D10Device* pDevice)
{
        m_bCastShadow = true;
        CreateEffect(contentManager, pDevice);
        m_Texture = contentManager->GetTexture(pDevice, _T("./Bitmaps/grass.dds"));
}

void DX10ObjMesh::Initialize(ContentManager* contentManager)
{
        CreateEffect( contentManager );
}

void DX10ObjMesh::Tick(const InputState& inputState)
{
        if ( IsAnimated() )
                m_pSkeleton->Animate(inputState.GetDeltaTime()*20);
}


void DX10ObjMesh::Draw(const RenderContext* renderContext, ID3D10ShaderResourceView* shadowdepthmap)
{
		if(!m_bEnableDraw)
			return;
        Draw(renderContext, m_pDefaultTechnique);
}

       
void DX10ObjMesh::Draw(const RenderContext* renderContext, const ID3D10EffectTechnique* pTechnique)
{
        ID3D10Device* pDevice = m_pLevel->GetDevice();
       
        if(!pTechnique)
        {
                MessageBox(0,_T("No Technique"),_T("ERROR"),0);
                return;
        }

        //Every object has it's own set of eg worldmatrix
        UpdateEffectVariables(renderContext);

        // Set the input layout
        pDevice->IASetInputLayout( m_pInputLayout );

        // Set primitive topology
        pDevice->IASetPrimitiveTopology( D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST );


        // Set vertex buffer
        UINT offset = 0;
        pDevice->IASetVertexBuffers( 0, 1, &m_pVertexBuffer, &m_VertexBufferStride, &offset );
        //
        // Renders a ShapeBase
        //
        D3D10_TECHNIQUE_DESC techDesc;
        (const_cast<ID3D10EffectTechnique*>(pTechnique))->GetDesc( &techDesc );
        for( UINT p = 0; p < techDesc.Passes; ++p )
        {
                vector<DX10MaterialIndexBuffer*>::const_iterator it;
                /*for (it=m_IndexBuffers.begin(); it != m_IndexBuffers.end(); ++it)
                {
                        ID3D10EffectPass * pass = (const_cast<ID3D10EffectTechnique*>(pTechnique))->GetPassByIndex( p );
                        (*it)->Draw(pDevice,this,pass);
                }*/
                it = m_IndexBuffers.begin();
                ID3D10EffectPass * pass = (const_cast<ID3D10EffectTechnique*>(pTechnique))->GetPassByIndex( p );
                (*it)->Draw(pDevice,this,pass);
        }
}

void DX10ObjMesh::OnResize()
{
}
void DX10ObjMesh::DrawToShadowmap(GraphCamera* pOrtohCam, D3DXMATRIX &mLightVolume
        ,ID3D10Effect* BuildShadowMapFX)
{
        m_OrthoCam = pOrtohCam;

        ID3D10EffectTechnique* m_pBuildShadowTechnique;

        m_pBuildShadowTechnique = BuildShadowMapFX->GetTechniqueByName("BuildShadowMapTech");
        if(!m_pBuildShadowTechnique->IsValid())MessageBox(0,_T("Technique not valid"),_T("ERROR"),0);

        if(mfxBuildShadowMapDiffuseMapVar == 0)
                mfxBuildShadowMapDiffuseMapVar = BuildShadowMapFX->GetVariableByName("gDiffuseMap")->AsShaderResource();
        if(mfxBuildShadowMapLightWVPVar == 0)
                mfxBuildShadowMapLightWVPVar   = BuildShadowMapFX->GetVariableByName("gLightWVP")->AsMatrix();

        Light temp;
        RenderContext renderContext(pOrtohCam, temp);

        D3D10_TECHNIQUE_DESC techDesc;
    m_pBuildShadowTechnique->GetDesc( &techDesc );
        m_pLevel->GetDevice()->IASetInputLayout( m_pInputLayout );

    for(UINT i = 0; i < techDesc.Passes; ++i)
    {
        ID3D10EffectPass* pass = m_pBuildShadowTechnique->GetPassByIndex(i);

                D3DXMATRIX floorWVP = m_World*pOrtohCam->GetView()*mLightVolume;
                mfxBuildShadowMapLightWVPVar->SetMatrix((float*)&floorWVP);
                mfxBuildShadowMapDiffuseMapVar->SetResource(m_Texture);
                pass->Apply(0);
                //Draw

                Draw(&renderContext, m_pDefaultTechnique);
    }
}
